﻿using System.Linq.Expressions;
using Devonline.AspNetCore;
using Devonline.Entity;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

namespace Devonline.Database.NoSQL;

/// <summary>
/// NoSQL 数据库服务的默认抽象实现
/// </summary>
public abstract class NoSQLDataService(
    ILogger<NoSQLDataService> logger,
    IDatabaseEndpoint endpoint,
    IHttpContextAccessor httpContextAccessor
    ) : INoSQLDataService
{
    /// <summary>
    /// 日志
    /// </summary>
    protected readonly ILogger<NoSQLDataService> _logger = logger;
    /// <summary>
    /// 数据库连接终结点配置
    /// </summary>
    protected readonly IDatabaseEndpoint _endpoint = endpoint;
    /// <summary>
    /// Http Context
    /// </summary>
    protected readonly HttpContext _httpContext = httpContextAccessor.HttpContext!;
    /// <summary>
    /// Http Request
    /// </summary>
    protected readonly HttpRequest _request = httpContextAccessor.HttpContext!.Request;

    /// <summary>
    /// 写入一行数据到数据库
    /// </summary>
    /// <typeparam name="TModel">数据对象模型的类型</typeparam>
    /// <param name="model">待写入的数据</param>
    /// <returns></returns>
    public virtual Task AddAsync<TModel>(TModel model) where TModel : class, new() => ExecuteAsync(async () => await InternalAddAsync<TModel>(model));
    /// <summary>
    /// 写入多行数据到数据库
    /// </summary>
    /// <typeparam name="TModel">数据对象模型的类型</typeparam>
    /// <param name="data">待写入的数据</param>
    /// <returns></returns>
    public virtual Task AddsAsync<TModel>(IEnumerable<TModel> data) where TModel : class, new() => ExecuteAsync(async () => await InternalAddsAsync<TModel>(data));

    /// <summary>
    /// 更新一行记录到数据库
    /// </summary>
    /// <typeparam name="TModel">数据对象模型的类型</typeparam>
    /// <param name="model">要更新的数据</param>
    /// <returns></returns>
    public virtual Task UpdateAsync<TModel>(TModel model) where TModel : class, IEntitySet, new() => ExecuteAsync(async () => await InternalUpdateAsync<TModel>(model));
    /// <summary>
    /// 更新多行记录到数据库
    /// </summary>
    /// <typeparam name="TModel">数据对象模型的类型</typeparam>
    /// <param name="data">要更新的数据</param>
    /// <returns></returns>
    public virtual Task UpdatesAsync<TModel>(IEnumerable<TModel> data) where TModel : class, IEntitySet, new() => ExecuteAsync(async () => await InternalUpdatesAsync<TModel>(data));

    public abstract Task DeleteAsync<TModel, TKey>(TKey id, DataServiceContext? context = null) where TModel : class, IEntitySet;
    public abstract Task DeletesAsync<TModel, TKey>(IEnumerable<TKey> ids, DataServiceContext? context = null) where TModel : class, IEntitySet;

    public abstract Task<IQueryable<TModel>> GetQueryableAsync<TModel>() where TModel : class, new();
    public abstract Task<IQueryable<TModel>> GetQueryableAsync<TModel>(Expression<Func<TModel, bool>> predicate) where TModel : class, new();
    public abstract Task<TModel?> FirstOrDefaultAsync<TModel>(Expression<Func<TModel, bool>> predicate) where TModel : class, new();
    /// <summary>
    /// 从数据库查询多行数据
    /// </summary>
    /// <typeparam name="TModel">数据对象模型的类型</typeparam>
    /// <returns></returns>
    public abstract Task<PagedResult<TModel>> GetPagedResultAsync<TModel>() where TModel : class, new();
    public abstract Task<PagedResult<TModel>> GetPagedResultAsync<TModel>(Expression<Func<TModel, bool>> predicate) where TModel : class, new();

    /// <summary>
    /// 执行循环写入
    /// </summary>
    /// <param name="action">要执行的具体写入方法</param>
    /// <returns></returns>
    protected async Task ExecuteAsync(Func<Task> action)
    {
        var retry = 0;
        var success = false;
        var userName = _httpContext.GetUserName();
        while (!success && retry++ <= _endpoint.Retry)
        {
            try
            {
                _logger.LogDebug("用户 {userName} 将操作 {host} 的数据库 {database}", userName, _endpoint.Host, _endpoint.Database);
                await action();
                _logger.LogInformation("用户 {userName} 已操作 {host} 的数据库 {host}", userName, _endpoint.Host, _endpoint.Database);
                success = true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "用户 {userName} 将数据操作 {host} 的数据库 {host} 时出错!", userName, _endpoint.Host, _endpoint.Database);
            }
        }

        if (!success)
        {
            _logger.LogError("用户 {userName} 将数据操作 {host} 的数据库 {host} 时失败, 且经过 {retry} 次重新尝试均不能成功, 本次操作操作请检查问题后再做处理!", userName, _endpoint.Host, _endpoint.Database, _endpoint.Retry);
        }
    }
    /// <summary>
    /// 基于默认实现的内部写入方法
    /// </summary>
    /// <typeparam name="TModel">数据对象模型的类型</typeparam>
    /// <param name="model">待写入的数据</param>
    /// <returns></returns>
    protected abstract Task InternalAddAsync<TModel>(TModel model);
    /// <summary>
    /// 基于默认实现的内部写入方法
    /// </summary>
    /// <typeparam name="TModel">数据对象模型的类型</typeparam>
    /// <param name="data">待写入的数据</param>
    /// <returns></returns>
    protected abstract Task InternalAddsAsync<TModel>(IEnumerable<TModel> data);
    /// <summary>
    /// 基于默认实现的内部更新方法
    /// </summary>
    /// <typeparam name="TModel">数据对象模型的类型</typeparam>
    /// <param name="model">待更新的数据</param>
    /// <returns></returns>
    protected abstract Task InternalUpdateAsync<TModel>(TModel model) where TModel : IEntitySet;
    /// <summary>
    /// 基于默认实现的内部更新方法
    /// </summary>
    /// <typeparam name="TModel">数据对象模型的类型</typeparam>
    /// <param name="data">待更新的数据</param>
    /// <returns></returns>
    protected abstract Task InternalUpdatesAsync<TModel>(IEnumerable<TModel> data) where TModel : IEntitySet;
}